#pragma once

#include "Thread.hpp"
#include "Task.hpp"
#include "Lock.hpp"
#include "Log.hpp"

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <pthread.h>
#include <unistd.h>

const int g_def_queue_capacity = 5;
const int g_def_thread_num = 3;

template <class T>
class ThreadPool
{
public:
    ThreadPool(int queue_capacity = g_def_queue_capacity, int thread_num = g_def_thread_num)
        : _queue_capacity(queue_capacity), _thread_num(thread_num), _ptr_prod_queue(&_queue_1), _ptr_con_queue(&_queue_2)
    {
        // 初始化锁
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_Full, nullptr);
        pthread_cond_init(&_Empty, nullptr);

        // 创建生产者线程对象
        for (int i = 1; i <= _thread_num; ++i)
        {
            _prod_thread.push_back(new Thread(product, i, "Product Thread ", (void *)this));
        }

        // 创建消费者线程对象
        for (int i = 1; i <= _thread_num; ++i)
        {
            _con_thread.push_back(new Thread(consume, i, "Consume Thread ", (void *)this));
        }

        // 启动生产者线程
        for (const auto iter_prod : _prod_thread)
        {
            iter_prod->start();
        }

        // 启动消费者线程
        for (const auto iter_con : _con_thread)
        {
            iter_con->start();
        }
    }

    // 析构函数 -- delete每一个线程类
    ~ThreadPool()
    {
        for (const auto iter_prod : _prod_thread)
        {
            delete iter_prod;
        }

        for (const auto iter_con : _con_thread)
        {
            delete iter_con;
        }

        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_Full);
        pthread_cond_destroy(&_Empty);
    }

private:
    bool IsProdFull()
    {
        return _ptr_prod_queue->size() == _queue_capacity;
    }

    bool IsConEmpty()
    {
        return _ptr_con_queue->empty();
    }

    // 生产者线程函数
    static void *product(void *args)
    {
        ThreadData *pdata = (ThreadData *)args;
        ThreadPool<T> *ptr = (ThreadPool<T> *)pdata->_args;

        // 生产者开始向队列中写数据
        while (true)
        {
            // 生产者拿锁，检查临界资源
            // LockGuard prodLockGuard(&ptr->_mtx_prod);

            // 如果生产者队列满了，那么就交换指向队列的指针
            {
                LockGuard lockGuard(&ptr->_mtx);
                if (ptr->IsProdFull())
                {
                    std::swap(ptr->_ptr_con_queue, ptr->_ptr_prod_queue); // 指针交换
                    logMessage(DEBUG, "[%s] 指向生产者队列的指针和指向消费者队列的指针发生交换", pdata->_name.c_str());
                }

                // 如果此时生产队列还是满的，那么说明生产与消费者队列可能一直是满的
                // 需要阻塞等待条件变量
                while (ptr->IsProdFull())
                    pthread_cond_wait(&ptr->_Full, &ptr->_mtx);

                int x = rand() % 20 + 1;
                usleep(155);
                int y = rand() % 20 + 1;

                logMessage(DEBUG, "[%s] 制作任务成功：%d+%d=?", pdata->_name.c_str(), x, y);
                T task(x, y, [](int x, int y)
                       { return x + y; });
                ptr->_ptr_prod_queue->push(task);

                pthread_cond_signal(&ptr->_Empty);
            }
        }

        return nullptr;
    }

    // 消费者线程函数
    static void *consume(void *args)
    {
        ThreadData *pdata = (ThreadData *)args;
        ThreadPool<T> *ptr = (ThreadPool<T> *)pdata->_args;

        T task;
        while (true)
        {
            {
                // 消费者拿锁检查临界资源
                // LockGuard conLockGuard(&ptr->_mtx_con);

                // 检查消费者队列是否为空
                LockGuard lockGuard(&ptr->_mtx);
                if (ptr->IsConEmpty())
                {
                std:
                    swap(ptr->_ptr_con_queue, ptr->_ptr_prod_queue);
                    logMessage(DEBUG, "[%s] 指向生产者队列的指针和指向消费者队列的指针发生交换", pdata->_name.c_str());
                }

                // 如果此时生产消费还是空的，那么说明生产与消费者队列可能都是空的
                // 需要阻塞等待条件变量
                while (ptr->IsConEmpty())
                    pthread_cond_wait(&ptr->_Empty, &ptr->_mtx);
                // std::cout << "size = " << ptr->_ptr_con_queue->size() << std::endl;
                task = ptr->_ptr_con_queue->front();
                ptr->_ptr_con_queue->pop();

                logMessage(DEBUG, "[%s] 执行完成一个任务: %d+%d=%d", pdata->_name.c_str(), task.get_x(), task.get_y(), task());
                pthread_cond_signal(&ptr->_Full);
            }
        }

        return nullptr;
    }

private:
    std::vector<Thread *> _prod_thread; // 生产者线程
    std::vector<Thread *> _con_thread;  // 消费者线程
    int _queue_capacity;                // 生产和消费者队列的最大容量
    int _thread_num;                    // 线程数量
    std::queue<T> _queue_1;             // 阻塞队列1
    std::queue<T> _queue_2;             // 阻塞队列2
    std::queue<T> *_ptr_prod_queue;     // 指向生产者阻塞队列的指针
    std::queue<T> *_ptr_con_queue;      // 指向消费者阻塞队列的指针
    pthread_mutex_t _mtx;               // 生产与消费者访问共同资源拿的锁
    pthread_cond_t _Full;               // 控制生产者队列满的条件变量
    pthread_cond_t _Empty;              // 控制消费者队列空的条件变量
};